package com.bxw.forum.config;

import com.bxw.forum.common.AppResult;
import com.bxw.forum.common.ResultCode;
import com.bxw.forum.component.OnlineUserManager;
import com.bxw.forum.dao.MessageMapper;
import com.bxw.forum.exception.ApplicationException;
import com.bxw.forum.model.Message;
import com.bxw.forum.model.User;
import com.bxw.forum.model.WebSocketMessage;
import com.bxw.forum.service.IUserService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.Date;

@Component
@Slf4j
public class WebSocketAPI extends TextWebSocketHandler {

    @Resource
    OnlineUserManager onlineUserManager;
    @Resource
    ObjectMapper objectMapper;
    @Resource
    IUserService userService;
    @Resource
    MessageMapper messageMapper;


    /**
     * 开启链接用户上线
     * @param session
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        log.info("开启websocket链接");
        System.out.println(session.getAttributes());
        User user = (User) session.getAttributes().get(AppConfig.USER_SESSION);

        if (user == null) {
            throw new ApplicationException(AppResult.fail(ResultCode.FAILED_USER_NOT_EXISTS));
        }

        if (user.getState() != 0) {
            throw new ApplicationException(AppResult.fail(ResultCode.FAILED_USER_BANNED));
        }

        onlineUserManager.online(user.getId(),session);

    }


    /**
     * 关闭链接用户下线
     * @param session
     * @param status
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        log.info("关闭websocket链接");

        User user = (User)session.getAttributes().get(AppConfig.USER_SESSION);

        if (user == null) {
            throw new ApplicationException(AppResult.fail(ResultCode.FAILED_USER_NOT_EXISTS));
        }

        if (user.getState() != 0) {
            throw new ApplicationException(AppResult.fail(ResultCode.FAILED_USER_BANNED));
        }

        onlineUserManager.offline(user.getId(),session);
    }

    /**
     * 处理异常
     * @param session
     * @param exception
     * @throws Exception
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        log.info("websocket发生异常");

        User user = (User)session.getAttributes().get(AppConfig.USER_SESSION);

        if (user == null) {
            throw new ApplicationException(AppResult.fail(ResultCode.FAILED_USER_NOT_EXISTS));
        }

        if (user.getState() != 0) {
            throw new ApplicationException(AppResult.fail(ResultCode.FAILED_USER_BANNED));
        }

        onlineUserManager.offline(user.getId(),session);
    }

    /**
     * 服务端接收到消息
     * @param session
     * @param message
     * @throws Exception
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        log.info("服务端接收到消息" + message.toString());

        User user = (User)session.getAttributes().get(AppConfig.USER_SESSION);

        if (user == null) {
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS.toString());
            throw new ApplicationException(AppResult.fail(ResultCode.FAILED_USER_NOT_EXISTS));
        }

        if (user.getState() != 0) {
            log.warn(ResultCode.FAILED_USER_BANNED.toString());
            throw new ApplicationException(AppResult.fail(ResultCode.FAILED_USER_BANNED));
        }

        WebSocketMessage webSocketMessage = objectMapper.readValue(message.getPayload(), WebSocketMessage.class);

        if(webSocketMessage.getType().equals("websocketmessage")) {
            System.out.println("Json序列化websocketmessage" + webSocketMessage);
            transferMessage(user,webSocketMessage);
        }else {
            System.out.println("Json序列化websocketmessage异常" + message.getPayload());
        }

    }

    private void transferMessage(User user, WebSocketMessage webSocketMessageRequest) throws IOException {
        // 在收到消息时已经校验过user
        // 在转发方法中校验receiveUser
        // 调用UserService通过receiveUserId查找到该用户
        // 构造转发消息的对象
        // 转成json序列化
        // 调用manger通过receiveUserId获取到session
        // 通过session转发消息
        Long postUserId = user.getId();
        Long receiveUserId =webSocketMessageRequest.getReceiveUserId();
        User receiveUser = userService.selectById(receiveUserId);

        if(receiveUser == null || receiveUser.getDeleteState() != 0) {
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS.toString());
            throw new ApplicationException(AppResult.fail(ResultCode.FAILED_USER_NOT_EXISTS));
        }

        if(receiveUserId == postUserId) {
            throw new ApplicationException(AppResult.fail("不能给自己发消息"));
        }

        Message webSocketMessage = new Message();
        webSocketMessage.setContent(webSocketMessage.getContent());
        webSocketMessage.setPostUserId(postUserId);
        webSocketMessage.setReceiveUserId(receiveUserId);
        webSocketMessage.setState((byte)0);
        webSocketMessage.setDeleteState((byte)0);
        Date date = new Date();
        webSocketMessage.setCreateTime(date);
        webSocketMessage.setUpdateTime(date);

        int row = messageMapper.insertSelective(webSocketMessage);

        webSocketMessage.setPostUser(user);

        String webSocketMessageRespond = objectMapper.writeValueAsString(webSocketMessage);
        System.out.println("打印json序列化后的信息" + webSocketMessageRespond);

        WebSocketSession existWebSocketSession = onlineUserManager.getSession(receiveUserId);

        if(existWebSocketSession != null) {
            existWebSocketSession.sendMessage(new TextMessage(webSocketMessageRespond));
        }

        if(row != 1) {
            log.warn(ResultCode.ERROR_SERVICES.toString());

            throw new ApplicationException(AppResult.fail(ResultCode.ERROR_SERVICES));
        }

    }
}
